﻿#include "AppWindow.h"


/// <summary>
/// 模拟线程中断
/// </summary>
/// <param name="time"></param>
void pauseThread(int time) {
	if (time > 0) {
		qint64 beginTime = TimeUtils::getTimeGen();
		while (TimeUtils::getTimeGen() - beginTime < time) {
			QApplication::processEvents();
		}
	}
}

AppWindow::AppWindow(SplashScreen& splash, QWidget* parent) 
	: QWidget(nullptr), m_splash(splash), m_config(Configuration::getInstance()) {
	// 注册数据类型到QT模型中
	//注册Mat
	qRegisterMetaType<cv::Mat>("cv::Mat");
	qRegisterMetaType<cv::Mat>("cv::Mat&");
	qRegisterMetaType<DetectResult>("DetectResult");
	qRegisterMetaType<DetectResult>("DetectResult&");

}

AppWindow::~AppWindow() {
	if (m_imageProcessTask != nullptr) {
		delete m_imageProcessTask;
	}
	if (m_serialPort.isOpen()) {
		m_serialPort.close();
	}
	if (m_scannerCamera.isOpened()) {
		m_scannerCamera.deleteLater();
	}
}

void AppWindow::init() {
    //季度条百分比
    int progress = 0;
    //初始化文件系统
    try {
		progress += 20;
        this->initFileSystem();
        m_splash.updateMsg("文件系统初始化成功...", progress);
    } catch (const RunError& e) {
		qCritical() << "文件系统初始化失败...";
		m_splash.updateMsg("文件系统初始化失败...", progress);
    }
    //初始化数据库
    try {
		progress += 20;
		initDataBase();
		m_splash.updateMsg("数据库连接成功...", progress);
    } catch (const RunError& e) {
		qCritical() << "数据库连接失败...";
		m_splash.updateMsg("数据库连接失败...", progress);
    }
    //初始化串口
    try {
		progress += 20;
        initSerialport();
		m_splash.updateMsg("串口连接成功...", progress);
    } catch (const RunError& e) {
		qCritical() << "串口连接失败...";
		m_splash.updateMsg("串口连接失败...", progress);
    }
    //连接扫描相机
    try {
		progress += 20;
		openScannerCamera();
		m_splash.updateMsg("扫描相机连接成功...", progress);
    } catch (const RunError& e) {
		qCritical() << "扫描相机连接失败...";
		m_splash.updateMsg("扫描相机连接失败...", progress);
    }
    //连接轮廓提取相机
    try {
		progress += 20;
		openSliderCapture();
		m_splash.updateMsg("轮廓提取相机连接成功...", progress);
    } catch (const RunError& e) {
		qCritical() << "轮廓提取相机打开失败...";
		m_splash.updateMsg("轮廓提取相机打开失败...", progress);
    }
	//初始化UI
	this->initUI();
}

void AppWindow::singleClicked(std::function<void()> f_display, int timeout) {
	QWidget* obj = qobject_cast<QWidget*>(this->sender());
	if (obj->isEnabled()) {
		obj->setEnabled(false);
		QCoreApplication::processEvents();
		f_display();
		QTimer::singleShot(timeout, [=]() {
			obj->setEnabled(true); });
	}
}

void AppWindow::initFileSystem() {
	try {
		qInfo() << tr("初始化文件系统...");
		//创建日志和缓存文件夹
		FileUtils::createDir(m_config.log.path);
		qInfo() << tr("删除过期文件...");
		//删除过期的日志
		FileUtils::deleteExpiresFiles(m_config.log.path, QDateTime::currentDateTime().addDays(-m_config.log.saveDays));
		//删除过期的图片缓存
		FileUtils::deleteExpiresFiles(m_config.cache.path, QDateTime::currentDateTime().addDays(-m_config.cache.saveDays));
		qInfo() << tr("文件系统初始化完成...");
	} catch (const std::exception& e) {
		qCritical() << e.what();
		throw RunError(RunError::FILE_CREATE_ERROR);
	} catch (...) {
		qCritical() << "UNKNOW ERROR...";
	}
}

void AppWindow::initDataBase() {
	try {
		qInfo() << tr("开始初始化数据库...");
		if (Dao::initDatabase()) {
			if (m_dao.openDb()) {
				qInfo() << tr("数据库连接成功...");
			} else {
				qWarning() << tr("数据库连接失败...");
				throw RunError(RunError::SQL_CONNECT_ERROR);
			}
		}
	} catch (const RunError& e) {
		qCritical() << e.errorMsg();
		throw e;
	}
}

void AppWindow::initSerialport() {
	try {
		//打开串口
		qInfo() << "开始连接串口...";
		if (m_serialPort.openPort("")) {
			qInfo() << "串口连接成功...";
			//关灯
			switchLedOff();
			//将平台复位
			m_serialPort.resetMoto();
		}
	} catch (const RunError& e) {
		qCritical() << e.errorMsg();
		throw e;
	} catch (const std::exception& e) {
		qCritical() << e.what();
		throw RunError(RunError::SERIAL_CONNECT_ERROR);
	}
}

void AppWindow::openScannerCamera() {
	qInfo() << tr("正在连接扫描相机...");
	//打开相机，若相机打开失败并且用户选择了忽略这个问题，则返回TRUE使程序继续运行
	try {
		if (m_scannerCamera.open()) {
			qInfo() << "扫描相机连接成功...";
			connect(&m_scannerCamera, &Camera::updateFrame, this, &AppWindow::onScannerFrameUpload);
			m_scannerCamera.setExposureTime(m_config.camera.exposure);
			m_scannerCamera.setGain(m_config.camera.gain);
		}
	} catch (const RunError& e) {
		qCritical() << e.errorMsg();
		throw e;
	} catch (const std::exception& e) {
		qCritical() << e.what();
		throw RunError(RunError::CAMERA_LOST);
	}
}

void AppWindow::openSliderCapture() {
	//连接显示图片的槽
	connect(&m_sliderCapture, &SliderCaptureTask::onUploadFrame, this, [&](const cv::Mat& frame) {
		//获取显示图像的标签
		QLabel* label = this->findChild<QLabel*>("mSliderLiveLabel");
		if (label->isVisible()) {
			try {
				if (!frame.empty()) {
					//将图片缩放至和Label尺寸相同
					cv::Mat img;
					QSize ls = label->size();
					cv::resize(frame, img, cv::Size(ls.width(), ls.height()));
					//绘制网格
					int rowStep = cvRound(ls.height() / 4);
					//绘制横向线条
					int row0 = cvRound(ls.height() / 2.0), row1 = row0;
					//绘制中间线
					cv::line(img, cv::Point(0, row0), cv::Point(img.cols, row0), cv::Scalar(0, 0, 255), 1);
					//绘制边线
					while (row0 >= rowStep && row1 < img.rows - rowStep) {
						row0 -= rowStep;
						row1 += rowStep;
						cv::line(img, cv::Point(0, row0), cv::Point(img.cols, row0), cv::Scalar(0, 0, 255), 1);
						cv::line(img, cv::Point(0, row1), cv::Point(img.cols, row1), cv::Scalar(0, 0, 255), 1);
					}
					//绘制纵向线条
					int colStep = cvRound(ls.width() / 4);
					int col0 = cvRound(ls.width() / 2.0), col1 = col0;
					//绘制中间线
					cv::line(img, cv::Point(col0, 0), cv::Point(col0, img.rows), cv::Scalar(0, 0, 255), 1);
					while (col0 >= colStep && col1 < img.cols - colStep) {
						col0 -= colStep;
						col1 += colStep;
						cv::line(img, cv::Point(col0, 0), cv::Point(col0, img.rows), cv::Scalar(0, 0, 255), 1);
						cv::line(img, cv::Point(col1, 0), cv::Point(col1, img.rows), cv::Scalar(0, 0, 255), 1);
					}
					ImageUtils::liveImage(label, img.clone());
				}
			} catch (const std::exception& e) {
				qCritical() << e.what();
			}
		}
	});
	//连接显示图片的槽
	connect(&m_sliderCapture, &SliderCaptureTask::runStatus, this, [&](int status) {
		if (RunError::CAMERA_LOST == status) {
			if (MyMessageBox::warning(this, tr("顶部相机失去连接"), tr("重连"), tr("关闭"))) {
				m_sliderCapture.resume();
			} else {
				m_sliderCapture.stop();
			}
		}
	});
	//启动线程
	m_sliderCapture.start();
}

void AppWindow::initImageProcessTask() {
	connect(m_imageProcessTask, &ImageProcessTask::finished, this, [&]() {
		//关闭等待框
		WaitDlg::closeDlg();
		//判断检测中是否出现错误
		RunError error = m_imageProcessTask->getError();
		if (error.type() == RunError::NONE_ERROR) {
			DetectResult result = m_imageProcessTask->getResult();
			cv::Mat& img = result.markImg;
			if (img.cols < img.rows) {
				//将图片横过来
				cv::transpose(img, img);
				cv::flip(img, img, 1);
			}
			ImageUtils::liveImage(m_scannerImageLabel, img);
			//显示和保存结果
			processTestResult(m_imageProcessTask->getResult());
		} else {
			MyMessageBox::warning(this, error.errorMsg(), "关闭");
		}
		//释放指针
		m_imageProcessTask->deleteLater();
	});
}

void AppWindow::initUI() {
	//绑定信号和槽
	//连接菜单按钮的信号和槽函数
	connect(this->findChild<QAbstractButton*>("demarcateBtn"), &QAbstractButton::clicked, this, &AppWindow::onMenuBtnClicked);
	connect(this->findChild<QAbstractButton*>("settingBtn"), &QAbstractButton::clicked, this, &AppWindow::onMenuBtnClicked);
	connect(this->findChild<QAbstractButton*>("measureBtn"), &QAbstractButton::clicked, this, &AppWindow::onMenuBtnClicked);
	connect(this->findChild<QAbstractButton*>("queryBtn"), &QAbstractButton::clicked, this, &AppWindow::onMenuBtnClicked);
	connect(this->findChild<QAbstractButton*>("aboutBtn"), &QAbstractButton::clicked, this, &AppWindow::onMenuBtnClicked);
	connect(this->findChild<QAbstractButton*>("homeBtn"), &QAbstractButton::clicked, this, &AppWindow::onMenuBtnClicked);
	//绑定灯开关的信号和槽
	connect(findChild<QCheckBox*>("sSwitchLedTopLightCheckBox"), &QCheckBox::stateChanged, this, &AppWindow::onSwitchLight);
	connect(findChild<QCheckBox*>("sSwitchLedSliderLightCheckBox"), &QCheckBox::stateChanged, this, &AppWindow::onSwitchLight);
	connect(findChild<QCheckBox*>("sSwitchLedBottomLightCheckBox"), &QCheckBox::stateChanged, this, &AppWindow::onSwitchLight);

	qInfo() << tr("加载界面...");
	this->setWindowTitle(m_config.equipment.chName);
	
	//设置项目名称，加载logo
	this->findChild<QLabel*>("chNameLabel")->setText(m_config.equipment.chName);
	this->findChild<QLabel*>("enNameLabel")->setText(m_config.equipment.enName);
	QLabel* headerLogoLabel = this->findChild<QLabel*>("headerLogoLabel");
	QLabel* homeLogoLabel = this->findChild<QLabel*>("homeLogoLabel");
	m_config.logoPath.headerLogo.isEmpty() ? headerLogoLabel->clear() : headerLogoLabel->setPixmap(QPixmap(m_config.logoPath.headerLogo));
	m_config.logoPath.homeLogo.isEmpty() ? homeLogoLabel->clear() : homeLogoLabel->setPixmap(QPixmap(m_config.logoPath.homeLogo));
	QLabel* systemNameLabel = this->findChild<QLabel*>("systemNameLabel");
	if (systemNameLabel != nullptr) {
		systemNameLabel->setText(m_config.equipment.chName + " " + m_config.equipment.enName);
	}
	
	//版本信息
	this->findChild<QLabel*>("equipmentVersionLabel")->setText(QString("仪器版本：%1").arg(m_config.equipment.version));
	this->findChild<QLabel*>("mechanicalVersionLabel")->setText(QString("电子版本：%1").arg(m_config.equipment.eVersion));

	//联系我们
	this->findChild<QLabel*>("phoneNumberLabel")->setText(tr("联系电话：%1").arg(m_config.about.phone));
	this->findChild<QLabel*>("addressLabel")->setText(tr("联系地址：%1").arg(m_config.about.address));
	
	//初始化表格显示
	this->initTable();

	//====== 相机参数初始化 ============
	((SpinBox*)this->findChild<QWidget*>("cameraExposureTimeSpinBox"))->setValue(m_config.camera.exposure);
	((SpinBox*) this->findChild<QWidget*>("cameraGainSpinBox"))->setValue(m_config.camera.gain);
	//标定结果
	this->findChild<QLabel*>("demarcateResultLabel")->setText(tr("%1mm/pix").arg(QString::number((m_config.camera.pixsizeX + m_config.camera.pixsizeY) / 2.0f, 'f', 3)));
	this->findChild<QLabel*>("demarcateCheckLabel")->setText(tr("长度：0mm,  宽度：0mm"));

	//====== 判断是否显示参数配置页 ============
	this->findChild<QFrame*>("configSettingFrame")->setVisible(m_config.env.devModel);
	this->findChild<QFrame*>("testFrame")->setVisible(m_config.env.devModel);
	//======== 页面初始化 ==============
	m_config.env.fullScreen ? this->showFullScreen() : this->show();

	//查询检测参数
	queryTestParams();
	//======== 查询菜单初始化 ==============
	//初始化查询日期
	QDate today = QDate::currentDate();
	this->findChild<QDateEdit*>("qBeginDateEdit")->setDate(today);
	this->findChild<QDateEdit*>("qEndDateEdit")->setDate(today);
	//======= 检测参数初始化 ===========
	resetTestParams();
}

void AppWindow::initTable() {
	//表头
	QStringList header;
	header << "编号" << "烟支面积\n(mm²)" << "警语区面积\n(mm²)" << "分割线宽\n(mm)" << "文字高度\n(mm)" << "文字面积\n(mm²)" << "警语区占比\n(%)" << "文字占比\n(%)" << "色差";
	
	//检测记录表格
	QTableWidget* table = findChild<QTableWidget*>("mResultTable");
	table->horizontalHeader()->setVisible(true);
	table->setHorizontalHeaderLabels(header);
	table->setRowCount(m_testTableMinRow);

	
	//历史记录表格
	table = findChild<QTableWidget*>("qResultTable");
	table->horizontalHeader()->setVisible(true);
	table->setRowCount(m_historyTableMinRow);

	//历史数据表格
	table = findChild<QTableWidget*>("qResultTable_2");
	table->horizontalHeader()->setVisible(true);
	table->setHorizontalHeaderLabels(header);
	table->setRowCount(m_historyDataTableMinRow);

	//牌号信息表格
	table = findChild<QTableWidget*>("sBrandTableWidget");
	table->horizontalHeader()->setVisible(true);
	table->setRowCount(m_brandTableMinRow);

	//检测员信息表格
	table = findChild<QTableWidget*>("sTesterTableWidget");
	table->horizontalHeader()->setVisible(true);
	table->setRowCount(m_testerTableMinRow);

	//班次表格
	table = findChild<QTableWidget*>("sScheduleTableWidget");
	table->horizontalHeader()->setVisible(true);
	table->setRowCount(m_scheduleTableMinRow);

}

void AppWindow::addTester(QString tester) {
	if (!tester.isEmpty()) {
		try {
			QComboBox* box = findChild<QComboBox*>("mTesterComboBox");
			QTableWidget* table = findChild<QTableWidget*>("sTesterTableWidget");
			//判断是否存在相同的记录
			if (box->findText(tester) == -1) {
				m_dao.addTestParam("tester", tester);
				box->insertItem(0, tester);
				//重置设置表格中的数据
				TableUtils::restTable(table, max(m_testerTableMinRow, box->count()));
				for (int i = 0; i < box->count(); i++) {
					TableUtils::insertValue2Table(table, i, 0, i + 1);
					TableUtils::insertValue2Table(table, i, 1, box->itemData(i));
				}
			}
		} catch (const std::exception& e) {
			qCritical() << e.what();
		}
	}
}

void AppWindow::addBrand(QString brand) {
	if (!brand.isEmpty()) {
		try {
			QComboBox* box = findChild<QComboBox*>("mBrandComboBox");
			QTableWidget* table = findChild<QTableWidget*>("sBrandTableWidget");
			//判断是否存在相同的记录
			if (box->findText(brand) == -1) {
				m_dao.addTestParam("brand", brand);
				box->insertItem(0, brand);
				//向牌号表格中填充数据
				TableUtils::restTable(table, max(m_brandTableMinRow, box->count()));
				for (int i = 0; i < box->count(); i++) {
					TableUtils::insertValue2Table(table, i, 0, i + 1);
					TableUtils::insertValue2Table(table, i, 1, box->itemData(i));
				}
			}
		} catch (const std::exception& e) {
			qCritical() << e.what();
		}
	}
}

void AppWindow::addSchedule(QString schedule) {
	if (!schedule.isEmpty()) {
		try {
			QComboBox* box = findChild<QComboBox*>("mScheduleComboBox");
			QTableWidget* table = findChild<QTableWidget*>("sScheduleTableWidget");
			//判断是否存在相同的记录
			if (box->findText(schedule) == -1) {
				m_dao.addTestParam("schedule", schedule);
				box->insertItem(0, schedule);
				//向班次表格中填充数据
				TableUtils::restTable(table, max(m_scheduleTableMinRow, box->count()));
				for (int i = 0; i < box->count(); i++) {
					TableUtils::insertValue2Table(table, i, 0, i + 1);
					TableUtils::insertValue2Table(table, i, 1, box->itemData(i));
				}
			}
		} catch (const std::exception& e) {
			qCritical() << e.what();
		}
	}
}

void AppWindow::queryTestParams() {
	try {
		if (!m_dao.isOpened()) {
			return;
		}
		QComboBox* mTesterComboBox = findChild<QComboBox*>("mTesterComboBox");
		QComboBox* mBrandComboBox = findChild<QComboBox*>("mBrandComboBox");
		QComboBox* mScheduleComboBox = findChild<QComboBox*>("mScheduleComboBox");
		QTableWidget* sTesterTableWidget = findChild<QTableWidget*>("sTesterTableWidget");
		QTableWidget* sBrandTableWidget = findChild<QTableWidget*>("sBrandTableWidget");
		QTableWidget* sScheduleTableWidget = findChild<QTableWidget*>("sScheduleTableWidget");
		//检测员，牌号，班次列表
		QStringList testerList, brandList, scheduleList;
		m_dao.queryTestParam("tester", testerList);
		m_dao.queryTestParam("brand", brandList);
		m_dao.queryTestParam("schedule", scheduleList);
		//清空下拉框中的数据
		mTesterComboBox->clear();
		mBrandComboBox->clear();
		mScheduleComboBox->clear();
		//填充下拉框中的数据
		mTesterComboBox->addItems(testerList);
		mBrandComboBox->addItems(brandList);
		mScheduleComboBox->addItems(scheduleList);
		//重置表格行数，并填充数据
		TableUtils::restTable(sTesterTableWidget, max(m_testerTableMinRow, testerList.size()));
		TableUtils::restTable(sBrandTableWidget, max(m_brandTableMinRow, brandList.size()));
		TableUtils::restTable(sScheduleTableWidget, max(m_scheduleTableMinRow, scheduleList.size()));
		//向检测员表格中填充数据
		for (int i = 0; i < testerList.size(); i++) {
			TableUtils::insertValue2Table(sTesterTableWidget, i, 0, i + 1);
			TableUtils::insertValue2Table(sTesterTableWidget, i, 1, testerList[i]);
		}
		//向牌号表格中填充数据
		for (int i = 0; i < brandList.size(); i++) {
			TableUtils::insertValue2Table(sBrandTableWidget, i, 0, i + 1);
			TableUtils::insertValue2Table(sBrandTableWidget, i, 1, brandList[i]);
		}
		//向班次表格中填充数据
		for (int i = 0; i < scheduleList.size(); i++) {
			TableUtils::insertValue2Table(sScheduleTableWidget, i, 0, i + 1);
			TableUtils::insertValue2Table(sScheduleTableWidget, i, 1, scheduleList[i]);
		}
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}

}

void AppWindow::queryHistoryTestParams() {
	if (!m_dao.isOpened()) {
		return;
	}
	try {
		QComboBox* qTesterComboBox = findChild<QComboBox*>("qTesterComboBox");
		QComboBox* qBrandComboBox = findChild<QComboBox*>("qBrandComboBox");
		QComboBox* qScheduleComboBox = findChild<QComboBox*>("qScheduleComboBox");
		//检测员，牌号，班次列表
		QStringList testerList, brandList, scheduleList;
		m_dao.queryHistoryTestParams(brandList, testerList, scheduleList);
		//清空下拉框中的数据
		qTesterComboBox->clear();
		qBrandComboBox->clear();
		qScheduleComboBox->clear();
		//填充数据
		qTesterComboBox->addItems(testerList);
		qBrandComboBox->addItems(brandList);
		qScheduleComboBox->addItems(scheduleList);
		//清空选项
		qTesterComboBox->setCurrentIndex(-1);
		qBrandComboBox->setCurrentIndex(-1);
		qScheduleComboBox->setCurrentIndex(-1);
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}

}

void AppWindow::queryTestRecord(QDate& beginDay, QDate& endDay, QString tester, QString schedule, QString brand) {
	if (!m_dao.isOpened()) {
		return;
	}
	try {
		QTableWidget* table = findChild<QTableWidget*>("qResultTable_2");

		TableUtils::restTable(table, m_historyDataTableMinRow);
		table = findChild<QTableWidget*>("qResultTable");
		//查询记录
		m_queryResultList.clear();
		//查询参数
		DaoModel::TestRecord params(tester, schedule, brand, "");
		//查询数据
		m_dao.queryTestRecords(m_queryResultList, params, beginDay, endDay);
		//清空表格,保证表格的行数不低于HISTORY_TABLE_ROW_MIN
		TableUtils::restTable(table, max(m_queryResultList.size(), m_historyTableMinRow));
		//想表格中填充数据
		for (int i = 0; i < m_queryResultList.size(); i++) {
			DaoModel::TestRecord& record = m_queryResultList[i];
			//序号
			TableUtils::insertValue2Table(table, i, 0, i + 1);
			//检测时间
			TableUtils::insertValue2Table(table, i, 1, record.testTime().toString(DATETIME_FORMAT));
			//牌号
			TableUtils::insertValue2Table(table, i, 2, record.brand());
			//检测员
			TableUtils::insertValue2Table(table, i, 3, record.tester());
			//班次
			TableUtils::insertValue2Table(table, i, 4, record.schedule());
			//检测编号
			TableUtils::insertValue2Table(table, i, 5, record.testNum());
		}
	} catch (const RunError& e) {
		qCritical() << e.errorMsg();
		throw e;
	} catch (const std::exception& e) {
		qCritical() << e.what();
		throw e;
	}
}

void AppWindow::showTestData(QTableWidget* table, QList<DaoModel::TestData>& dataList, int minRows) {
	//重置表格
	TableUtils::restTable(table, max(dataList.size(), minRows));
	for (int row = 0; row < dataList.size(); row++) {
		//获取数据
		DaoModel::TestData& data = dataList[row];
		//插入数据
		//编号
		TableUtils::insertValue2Table(table, row, 0, data.num());
		//烟弹/烟具的面积
		TableUtils::insertValue2Table(table, row, 1, data.area(), m_config.accuracy.area);
		//警语区面积
		TableUtils::insertValue2Table(table, row, 2, data.warningArea(), m_config.accuracy.area);
		//分割线宽度
		TableUtils::insertValue2Table(table, row, 3, data.lineWidth());
		//字体高度
		TableUtils::insertValue2Table(table, row, 4, data.textHeight());
		//文字面积
		TableUtils::insertValue2Table(table, row, 5, data.textArea(), m_config.accuracy.area);
		//警语区占比
		TableUtils::insertValue2Table(table, row, 6, data.warningAreaRatio());
		//文字占比
		TableUtils::insertValue2Table(table, row, 7, data.textAreaRatio());
	}
}

void AppWindow::setBtnsEnable(bool enable) {
	findChild<QAbstractButton*>("mTestBtn")->setEnabled(enable);
	findChild<QAbstractButton*>("demarcateBtn")->setEnabled(enable);
	findChild<QAbstractButton*>("demarcateCheckBtn")->setEnabled(enable);
	findChild<QAbstractButton*>("sMotorToTailBtn")->setEnabled(enable);
	findChild<QAbstractButton*>("sMotorToHeadBtn")->setEnabled(enable);
	if (!enable) {
		this->m_btnEnable = false;
	} else {
		//延时10毫秒使按钮使能，防止按钮连续被点击
		QTimer::singleShot(50, [&]() {m_btnEnable = true; });
	}
	QApplication::processEvents();
}

void AppWindow::switchLedOn(int num) {
	if (!m_serialPort.isOpen()) {
		qWarning() << "serial port not connect...";
		return;
	}
	try {
		//开启顶灯
		if (num & SerialPort::TOP) {
			qInfo() << "开顶灯...";
			findChild<QCheckBox*>("sSwitchLedTopLightCheckBox")->setChecked(true);
		}
		//开启侧灯
		if (num & SerialPort::SLIDER) {
			qInfo() << "开侧灯...";
			findChild<QCheckBox*>("sSwitchLedSliderLightCheckBox")->setChecked(true);
		}
		//开启底灯
		if (num & SerialPort::BOTTOM) {
			qInfo() << "开底灯...";
			findChild<QCheckBox*>("sSwitchLedBottomLightCheckBox")->setChecked(true);
		}
		m_serialPort.ledOn(num);
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}
}

void AppWindow::switchLedOff(int num) {
	if (!m_serialPort.isOpen()) {
		qWarning() << "serial port not connect...";
		return;
	}
	try {
		//开启顶灯
		if (num & SerialPort::TOP) {
			qDebug() << "关顶灯...";
			findChild<QCheckBox*>("sSwitchLedTopLightCheckBox")->setChecked(false);
		}
		//开启侧灯
		if (num & SerialPort::SLIDER) {
			qDebug() << "关顶灯...";
			findChild<QCheckBox*>("sSwitchLedSliderLightCheckBox")->setChecked(false);
		}
		//开启底灯
		if (num & SerialPort::BOTTOM) {
			qDebug() << "关顶灯...";
			findChild<QCheckBox*>("sSwitchLedBottomLightCheckBox")->setChecked(false);
		}
		m_serialPort.ledOff(num);
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}

}

bool AppWindow::checkBeforeStart() {
	try {
		//判断是否是第一次检测，封装检测参数
		if (m_testRecord.dataList().empty()) {
			m_testRecord = DaoModel::TestRecord();
			//校验批次
			QLineEdit* mTestBatchLineEdit = findChild<QLineEdit*>("mTestBatchLineEdit");
			if (mTestBatchLineEdit->text().trimmed().isEmpty()) {
				MyMessageBox::warning(this, tr("请输入批次"), tr("关闭"));
				return false;
			} else {
				while (m_dao.existTestBatch(mTestBatchLineEdit->text().trimmed())) {
					if (MyMessageBox::warning(this, tr("当前批次已存在，是否自动生成"), tr("是"), tr("否"))) {
						mTestBatchLineEdit->setText(QDateTime::currentDateTime().toString("yyMMddHHmmss"));
					} else {
						return false;
					}
				}
			}
			//封装参数
			m_testRecord.setTester(findChild<QComboBox*>("mTesterComboBox")->currentText());
			m_testRecord.setSchedule(findChild<QComboBox*>("mScheduleComboBox")->currentText());
			m_testRecord.setBrand(findChild<QComboBox*>("mBrandComboBox")->currentText());
			m_testRecord.setTestNum(mTestBatchLineEdit->text().trimmed());
			//创建缓存文件夹
			this->createCacheDir();
			//禁用检测参数输入框
			findChild<QComboBox*>("mTesterComboBox")->setEnabled(false);
			findChild<QComboBox*>("mScheduleComboBox")->setEnabled(false);
			findChild<QComboBox*>("mBrandComboBox")->setEnabled(false);
			mTestBatchLineEdit->setEnabled(false);
		}
		//检查样本编号
		QLineEdit* mTestNumLineEdit = findChild<QLineEdit*>("mTestNumLineEdit");
		QString testNum = mTestNumLineEdit->text().trimmed();
		if (testNum.isEmpty()) {
			mTestNumLineEdit->setText(QDateTime::currentDateTime().toString("HHmmss"));
		}
		//检测样本编号是否重复
		while (m_dao.existSampleNum(m_testRecord.id(), mTestNumLineEdit->text().trimmed())) {
			if (MyMessageBox::warning(this, tr("当前样本编号已存在，是否自动生成"), tr("是"), tr("否"))) {
				mTestNumLineEdit->setText(QDateTime::currentDateTime().toString("HHmmss"));
			} else {
				return false;
			}
		}
	} catch (const RunError& e) {
		qCritical() << "type: " << e.type() << ", msg: " << e.errorMsg();
		MyMessageBox::warning(this, e.errorMsg(), "关闭");
		return false;
	} catch (const std::exception& e) {
		qCritical() << e.what();
		MyMessageBox::error(this, "发生异常", "关闭");
		return false;
	} catch (...) {
		qCritical() << "UNKNOW ERROR...";
		MyMessageBox::error(this, "发生未捕获的异常", "关闭");
		return false;
	}
	return true;
}

void AppWindow::startTest() {
	try {
		cv::Mat sliderImage;
		//判断是否要采集侧边图像
		if (findChild<QCheckBox*>("curvedCheckBox")->isChecked()) {
			switchLedOn(SerialPort::SLIDER);
			pauseThread(1000);
			m_sliderCapture.getFrame(sliderImage);
			switchLedOff(SerialPort::SLIDER);
			if (sliderImage.empty()) {
				MyMessageBox::warning(this, tr("获取轮廓图像失败"), tr("关闭"));
				return;
			}
			saveImage(sliderImage, "slider");
		}
		//扫描图像
		cv::Mat lightImage, blackImage;
		startImageScan(lightImage, blackImage);
		saveImage(lightImage, "light");
		saveImage(blackImage, "black");

		//saveImage(lightImage(Rect(0, 780, 4840, 720)), "_light");
		//saveImage(blackImage(Rect(0, 780, 4840, 720)), "_black");
	/*	cv::Mat subImage = lightImage - blackImage;
		saveImage(subImage, "sub");
		subImage = 255 - subImage;
		saveImage(subImage, "sub_inv");*/

		//显示对话框
		if (!lightImage.empty() && !blackImage.empty()) {
			//创建图像预处理对话框
			ImageProcessDlg* dlg = ImageProcessDlgFactory::createDlg(lightImage, blackImage, sliderImage, this);
			if (dlg->execDlg() == QDialog::Accepted) {
				WaitDlg::showDlg(this, tr("正在处理，请稍后..."));
				//获取目标图片，启动检测线程
				dlg->getSmokeBoxImage(lightImage, blackImage);
				//开始处理
				if (!lightImage.empty() && !blackImage.empty()) {
					//保存扫描的图像
					saveImage(lightImage, "box_light");
					saveImage(blackImage, "box_black");
					//获取警语区
					cv::Rect warningArea = dlg->getWarningAreaPos();
					//获取分割线
					vector<cv::Rect> linesPos = dlg->getLinesPos();
					//获取警语
					vector<cv::Rect> textsPos = dlg->getWarningTextPos();

					//cv::Mat temp = blackImage.clone();
					//for (cv::Rect& rect : linesPos) {
					//	cv::rectangle(temp, rect, cv::Scalar(0, 255, 0), 1);
					//}
					//for (cv::Rect& rect : textsPos) {
					//	cv::rectangle(temp, rect, cv::Scalar(0, 0, 255), 1);
					//}
					//saveImage(temp, "temp");

					//创建线程
					m_imageProcessTask = new ImageProcessTask(
						lightImage, blackImage,
						dlg->getWarningAreaPos(),   //获取警语区
						dlg->getLinesPos(),         //获取分割线
						dlg->getWarningTextPos(),   //获取警语文字的位置
						dlg->isSmokeBomb(), this);
					//初始化并启动线程
					this->initImageProcessTask();
					m_imageProcessTask->start();
				} else {
					MyMessageBox::warning(this, tr("请选择有效区域"), tr("关闭"));
				}
			}
			dlg->deleteLater();
		} else {
			MyMessageBox::warning(this, tr("扫描失败"), tr("关闭"));
		}
	} catch (const RunError& e) {
		qCritical() << e.errorMsg();
		MyMessageBox::warning(this, e.errorMsg(), tr("关闭"));
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}

}

void AppWindow::startImageScan(cv::Mat& lightImage, cv::Mat& blackImage) {
	//判断相机和串口是否连接
	if (!m_serialPort.isOpen()) {
		throw RunError(RunError::SERIAL_CONNECT_ERROR, tr("串口未连接"));
	}
	if (!m_scannerCamera.isOpened()) {
		throw RunError(RunError::CAMERA_LOST, tr("相机未连接"));
	}
	////执行扫描流程
	//try {
	//	//禁用按钮
	//	this->setBtnsEnable(false);
	//	//等待电机复位
	//	m_serialPort.resetMoto();
	//	//pauseThread();
	//	/*----------- 第一次扫描 -------------*/
	//	//打开顶光源和底光源
	//	switchLedOn(SerialPort::TOP | SerialPort::BOTTOM);
	//	//发送指令，开始移动相机扫描
	//	int waitTime = 6000;
	//	//int waitTime = m_serialPort.moveMotoToTail();
	//	m_serialPort.moveMotoToTail();
	//	m_scannerCamera.startCollect();
	//	//等待电机移动
	//	pauseThread(waitTime);
	//	//关灯
	//	switchLedOff(SerialPort::TOP | SerialPort::BOTTOM);
	//	//平台复位
	//	//pauseThread(m_serialPort.resetMoto());
	//	m_serialPort.resetMoto();
	//	//获取图片
	//	m_scannerCamera.getImgBuffer(lightImage);
	//	//waitTime = 0;
	//	if (!lightImage.empty()) {
	//		//m_scannerImage2 = img(cv::Rect(600, 0, img.cols - 600, img.rows)).clone();
	//		/*----------- 第二次扫描 -------------*/
	//		//开灯
	//		switchLedOn(SerialPort::BOTTOM);
	//		//发送指令，开始移动相机
	//		//waitTime = m_serialPort.moveMotoToTail();
	//		m_serialPort.moveMotoToTail();
	//		//正向扫描
	//		m_scannerCamera.startCollect();
	//		//等待电机移动
	//		pauseThread(waitTime);
	//		//关掉底灯
	//		switchLedOff(SerialPort::BOTTOM);
	//		//平台复位
	//		m_serialPort.resetMoto();
	//		//获取图片
	//		m_scannerCamera.getImgBuffer(blackImage);
	//	}
	//	//复原顶灯的状态
	//	if (findChild<QCheckBox*>("curvedCheckBox")->isChecked()) {
	//		switchLedOn(SerialPort::TOP);
	//	}
	//	//复原按钮状态
	//	this->setBtnsEnable(true);
	//	//waitTime > 0 ? QTimer::singleShot(waitTime, [&]() { this->setBtnsEnable(true); }) : this->setBtnsEnable(true);
	//} catch (const std::exception& e) {
	//	//启用按钮
	//	this->setBtnsEnable(true);
	//	qCritical() << e.what();
	//	throw RunError(RunError::UNKNOW_ERROR, tr("扫描失败-2"));
	//}


	//执行扫描流程
	try {
		//禁用按钮
		this->setBtnsEnable(false);
		//等待电机复位
		m_serialPort.resetMoto();
		/*----------- 第一次扫描 -------------*/
		//打开顶光源和底光源
		switchLedOn(SerialPort::TOP | SerialPort::BOTTOM);
		//发送指令，开始移动相机扫描
		m_scannerCamera.resetBuffer();
		m_serialPort.moveMotoToTail([&]() {
			//正向扫描
			m_scannerCamera.startCollect();
		});
		//关灯
		switchLedOff(SerialPort::TOP | SerialPort::BOTTOM);
		//平台复位
		m_serialPort.resetMoto();
		//获取图片
		lightImage = m_scannerCamera.getImgBufferOrigin().clone();
		//waitTime = 0;
		if (!lightImage.empty()) {
			/*----------- 第二次扫描 -------------*/
			//开灯
			switchLedOn(SerialPort::BOTTOM);
			m_scannerCamera.resetBuffer();
			//发送指令，开始移动相机
			m_serialPort.moveMotoToTail([&]() {
				//正向扫描
				m_scannerCamera.startCollect();
			});
			//关掉底灯
			switchLedOff(SerialPort::BOTTOM);
			//平台复位
			m_serialPort.resetMoto();
			//获取图片
			blackImage = m_scannerCamera.getImgBufferOrigin().clone();
		}
		//复原顶灯的状态
		if (findChild<QCheckBox*>("curvedCheckBox")->isChecked()) {
			switchLedOn(SerialPort::TOP);
		}
		//复原按钮状态
		this->setBtnsEnable(true);
		//waitTime > 0 ? QTimer::singleShot(waitTime, [&]() { this->setBtnsEnable(true); }) : this->setBtnsEnable(true);
	} catch (const std::exception& e) {
		//启用按钮
		this->setBtnsEnable(true);
		qCritical() << e.what();
		throw RunError(RunError::UNKNOW_ERROR, tr("扫描失败-2"));
	}
}

void AppWindow::processTestResult(DetectResult& testData) {
	try {
		//若是第一次上传的检测结果，则保存检测记录
		if (m_testRecord.dataList().empty()) {
			//添加检测记录
			m_dao.addTestRecord(m_testRecord);
			//检查并添加检测人员信息
			addTester(m_testRecord.tester());
			addBrand(m_testRecord.brand());
			addSchedule(m_testRecord.schedule());
		}
		//显示和保存检测数据
		DaoModel::TestData testData(testData, m_testRecord.id(), findChild<QLineEdit*>("mTestNumLineEdit")->text().trimmed());
		//获取检测结果
		m_testRecord.addData(testData);
		//显示检测结果
		showTestData(findChild<QTableWidget*>("mResultTable"), m_testRecord.dataList(), m_testTableMinRow);
		//保存检测结果
		m_dao.addTestData(testData);
	} catch (const RunError& e) {
		qCritical() << e.errorMsg();
		MyMessageBox::warning(this, e.errorMsg(), tr("关闭"));
	} catch (const std::exception& e) {
		qCritical() << e.what();
		MyMessageBox::warning(this, tr("数据保存异常-1"), tr("关闭"));
	} catch (...) {
		qCritical() << "数据保存异常-2";
		MyMessageBox::warning(this, tr("数据保存异常-2"), tr("关闭"));
	}
}

void AppWindow::resetTestParams() {
	//重置检测参数和检测数据
	m_testRecord = DaoModel::TestRecord();
	//初始化输入框
	findChild<QComboBox*>("mTesterComboBox")->setCurrentIndex(-1);
	findChild<QComboBox*>("mScheduleComboBox")->setCurrentIndex(-1);
	findChild<QComboBox*>("mBrandComboBox")->setCurrentIndex(-1);
	findChild<QLineEdit*>("mTestBatchLineEdit")->clear();
	findChild<QLineEdit*>("mTestNumLineEdit")->clear();
	//初始化开关按钮
	findChild<QCheckBox*>("curvedCheckBox")->setChecked(false);
	//启用输入框
	findChild<QComboBox*>("mTesterComboBox")->setEnabled(true);
	findChild<QComboBox*>("mScheduleComboBox")->setEnabled(true);
	findChild<QComboBox*>("mBrandComboBox")->setEnabled(true);
	findChild<QLineEdit*>("mTestBatchLineEdit")->setEnabled(true);
	findChild<QLineEdit*>("mTestNumLineEdit")->setEnabled(true);
	//启用开关
	findChild<QCheckBox*>("curvedCheckBox")->setEnabled(true);
}

void AppWindow::createCacheDir() {
	QString imgDir = QString("%1/%2/%3").arg(m_config.cache.path).arg(QDate::currentDate().toString("yyyy-MM-dd")).arg(m_testRecord.testNum());
	try {
		//创建缓存文件夹
		FileUtils::createDir(imgDir);
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}
}

void AppWindow::saveImage(cv::Mat& image, QString imageName) {
	QString imgDir = QString("%1/%2/%3").arg(m_config.cache.path).arg(QDate::currentDate().toString("yyyy-MM-dd")).arg(m_testRecord.testNum());
	try {
		if (!image.empty()) {
			cv::imwrite(QString("%1/%2_%3.jpg").arg(imgDir).arg(findChild<QLineEdit*>("mTestNumLineEdit")->text().trimmed()).arg(imageName).toStdString(), image);
		}
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}
}

void AppWindow::deleteImage(QDate testDay, QString testBatch, QString testNum) {
	try {
		QString filePath = QString("%1/%2/%3/%4").arg(m_config.cache.path).arg(testDay.toString("yyyy-MM-dd")).arg(testBatch).arg(testNum);
		FileUtils::deleteFile(QString("%1_light.jpg").arg(filePath));
		FileUtils::deleteFile(QString("%1_black.jpg").arg(filePath));
		FileUtils::deleteFile(QString("%1_slider.jpg").arg(filePath));
		FileUtils::deleteFile(QString("%1_light_select.jpg").arg(filePath));
		FileUtils::deleteFile(QString("%1_black_select.jpg").arg(filePath));
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}
}

void AppWindow::onScannerFrameUpload(const cv::Mat& frame) {
	if (m_scannerImageLabel != nullptr) {
		try {
			//显示图像
			ImageUtils::liveImage(m_scannerImageLabel, frame);
		} catch (const std::exception& e) {
			qCritical() << e.what();
		}
	}
}

void AppWindow::onSwitchLight(int state) {
	QObject* obj = sender();
	qInfo() << obj->objectName() << " state: " << state;
	try {
		if (state == 2) {
			if (obj == findChild<QCheckBox*>("sSwitchLedTopLightCheckBox")) {
				m_serialPort.ledOn(SerialPort::TOP);
			} else if (obj == findChild<QCheckBox*>("sSwitchLedSliderLightCheckBox")) {
				m_serialPort.ledOn(SerialPort::SLIDER);
			} else if (obj == findChild<QCheckBox*>("sSwitchLedBottomLightCheckBox")) {
				m_serialPort.ledOn(SerialPort::BOTTOM);
			}
		} else {
			if (obj == findChild<QCheckBox*>("sSwitchLedTopLightCheckBox")) {
				m_serialPort.ledOff(SerialPort::TOP);
			} else if (obj == findChild<QCheckBox*>("sSwitchLedSliderLightCheckBox")) {
				m_serialPort.ledOff(SerialPort::SLIDER);
			} else if (obj == findChild<QCheckBox*>("sSwitchLedBottomLightCheckBox")) {
				m_serialPort.ledOff(SerialPort::BOTTOM);
			}
		}
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}
}

void AppWindow::onMenuBtnClicked() {
	//获取被点击的按钮
	QAbstractButton* btn = qobject_cast<QAbstractButton*>(sender());
	qInfo() << btn->objectName() << " clicked...";
	if (!m_btnEnable) {
		if (btn->isCheckable()) {
			btn->setChecked(!btn->isChecked());
		}
		return;
	}
	//=============== 主页按钮被点击 ===================
	if (btn == findChild<QAbstractButton*>("homeBtn")) {
		//关闭侧边相机预览
		m_sliderCapture.startLive(false);
		//关灯
		switchLedOff();
		//页面跳转到第一页
		findChild<QStackedWidget*>("stackedWidget")->setCurrentIndex(0);
		return;
	}
	//页面跳转到菜单页
	findChild<QStackedWidget*>("stackedWidget")->setCurrentIndex(1);
	//================ 菜单按钮被点击 ===================
	//初始化按钮状态
	for (QAbstractButton* b : findChild<QFrame*>("menuBtnsFrame")->findChildren<QAbstractButton*>()) {
		b->setChecked(false);
	}
	//将当前按钮设置为选中状态
	btn->setChecked(true);
	int index = 0;
	if (btn == findChild<QAbstractButton*>("demarcateBtn")) {
		index = 0;
		m_scannerImageLabel = findChild<QLabel*>("sScannerImageLiveLabel");
	} else if (btn == findChild<QAbstractButton*>("settingBtn")) {
		index = 1;
	} else if (btn == findChild<QAbstractButton*>("measureBtn")) {
		index = 2;
		m_scannerImageLabel = findChild<QLabel*>("mScannerImageLiveLabel");
	} else if (btn == findChild<QAbstractButton*>("queryBtn")) {
		index = 3;
		//查询当天的数据
		queryHistoryTestParams();
		QDate today = QDate::currentDate();
		queryTestRecord(today, today);
	} else if (btn == findChild<QAbstractButton*>("aboutBtn")) {
		index = 4;
	}
	//跳转页面
	findChild<QStackedWidget*>("contentWidget")->setCurrentIndex(index);
	//若是检测界面，实时预览，否则关闭实时预览
	if (btn == findChild<QAbstractButton*>("measureBtn")) {
		QLabel* mSliderLiveLabel = findChild<QLabel*>("mSliderLiveLabel");
		//switchLedOn(SerialPort::SLIDER);
		mSliderLiveLabel->clear();
		m_sliderCapture.startLive(true);
		//若曲面被选择，开启光源
		if (findChild<QCheckBox*>("curvedCheckBox")->isChecked()) {
			switchLedOn(SerialPort::TOP | SerialPort::SLIDER);
		}
	} else {
		//关闭侧边相机预览
		m_sliderCapture.startLive(false);
		//关灯
		switchLedOff();
	}
}

void AppWindow::on_exitBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		if (MyMessageBox::warning(this, tr("点击【退出】退出程序"), tr("退出"), tr("取消"))) {
			//停止图像采集线程
			if (m_sliderCapture.isRunning()) {
				m_sliderCapture.stop();
			}
			//关闭串口
			if (m_serialPort.isOpen()) {
				m_serialPort.close();
			}
			//释放相机
			if (m_scannerCamera.isOpened()) {
				m_scannerCamera.deleteLater();
			}
			emit close();
			this->deleteLater();
			qInfo() << tr("程序退出...");
		}
	}, 50);
}

void AppWindow::on_shutdownBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	//开发模式下，不使用该按钮
	if (!m_config.env.devModel) {
		singleClicked([&]() {
			if (MyMessageBox::warning(this, tr("是否要关机"), tr("是"), tr("否"))) {
				system("shutdown -s -t 00");
			}
		}, 50);
	}
}

void AppWindow::on_curvedCheckBox_stateChanged(int state) {
	qInfo() << sender()->objectName() << " state " << state;
	try {
		if (state == 2) {
			//开灯
			switchLedOn(SerialPort::SLIDER | SerialPort::TOP);
			//switchLedOn();
		   //打开侧面相机
			if (m_sliderCapture.isOpened()) {
				//将flag的值设置成btnEnable的值是防止相机运动过程中侧边轮廓不贴合
				m_sliderCapture.setDrawContourFlag(m_btnEnable);
			}
		} else {
			//关灯
			switchLedOff();
			//不再绘制轮廓线
			m_sliderCapture.setDrawContourFlag(false);
		}
	} catch (const std::exception& e) {
		qCritical() << e.what();
	}
}

void AppWindow::on_mSaveSiderBackgroundBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		if (!m_sliderCapture.isOpened()) {
			MyMessageBox::warning(this, tr("相机未连接"), tr("关闭"));
			return;
		}
		//提示用户清理掉载物台上的物品
		if (MyMessageBox::warning(this, tr("请确保载物玻璃上无物体"), tr("确定"), tr("取消"))) {
			//打开光源
			//开灯
			switchLedOn(SerialPort::SLIDER | SerialPort::TOP);
			//等待图片刷新
			cv::Mat backgroundImage;
			QThread::msleep(1000);
			//获取侧边图像
			m_sliderCapture.getFrame(backgroundImage);
			//关灯
			if (!findChild<QCheckBox*>("curvedCheckBox")->isChecked()) {
				switchLedOff(SerialPort::SLIDER | SerialPort::TOP);
			}
			//保存图片
			if (!backgroundImage.empty()) {
				//保存背景图片
				cv::imwrite("slider.bmp", backgroundImage);
				MyMessageBox::information(this, tr("操作成功"), tr("关闭"));
			} else {
				MyMessageBox::warning(this, tr("操作失败"), tr("关闭"));
			}
		}
	}, 50);

}

void AppWindow::on_mResetBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		if (MyMessageBox::warning(this, tr("是否要重置检测参数"), tr("确定"), tr("取消"))) {
			//启用输入框
			findChild<QComboBox*>("mTesterComboBox")->setEnabled(true);
			findChild<QComboBox*>("mScheduleComboBox")->setEnabled(true);
			findChild<QComboBox*>("mBrandComboBox")->setEnabled(true);
			findChild<QLineEdit*>("mTestBatchLineEdit")->setEnabled(true);
			findChild<QLineEdit*>("mTestNumLineEdit")->setEnabled(true);
			//启用开关
			findChild<QCheckBox*>("curvedCheckBox")->setEnabled(true);
			//清空表格
			TableUtils::restTable(findChild<QTableWidget*>("mResultTable"), m_testTableMinRow);
			//重置检测参数
			m_testRecord.dataList().clear();
			m_testRecord = DaoModel::TestRecord();
		}
	}, 50);
}

void AppWindow::on_mTestBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	//if (!m_btnEnable) {
	//	return;
	//}
	////检查输入条件，判断是否允许开始检测
	//if (checkBeforeStart()) {
	//	//开始检测
	//	startTest();
	//}

	startTest();

	//cv::Mat lightImage, blackImage;
	//startImageScan(lightImage, blackImage);




}

void AppWindow::on_mExportBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		//判断是否有数据可以导出
		if (m_testRecord.dataList().size() > 0) {
			//获取文件保存的文件夹
			QString filePath = QFileDialog::getExistingDirectory(this, QString("保存"), FileUtils::getDesktopPath());
			if (!filePath.isEmpty()) {
				//文件保存路径/项目名_检测日期_检测编号
				QString fileNmae = tr("%1/ECWS100_%2_%3.xlsx").arg(filePath).arg(m_testRecord.testTime().toString("yyyyMMdd")).arg(m_testRecord.testNum());
				try {
					ExcelUtils::saveExcel(m_testRecord, fileNmae);
					MyMessageBox::information(this, tr("导出完成"), tr("关闭"));
				} catch (const std::exception& e) {
					qCritical() << e.what();
					MyMessageBox::warning(this, tr("导出失败"), tr("关闭"));
				}
			}
		} else {
			MyMessageBox::warning(this, tr("无可导出数据"), tr("关闭"));
			qWarning() << tr("无可导出数据");
		}
	}, 50);
}

void AppWindow::on_mPrintBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		//判断是否有数据可以导出
		if (m_testRecord.dataList().size() > 0) {
			PrinterManager::printDirect(m_testRecord);
		} else {
			MyMessageBox::warning(this, tr("没有数据可打印"), tr("关闭"));
			qWarning() << tr("没有数据可打印");
		}
	}, 50);
}

void AppWindow::on_mDeleteBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		//检测的烟支数量
		int dataSize = m_testRecord.dataList().size();
		if (dataSize > 0) {
			//获取选中的行
			QTableWidget* mResultTable = findChild<QTableWidget*>("mResultTable");
			QList<QTableWidgetItem*> items = mResultTable->selectedItems();
			if (items.size() > 0 && items[0]->row() < dataSize) {
				if (MyMessageBox::warning(this, tr("是否要删除当前选中的记录，删除后将无法恢复"), tr("是"), tr("否"))) {
					int index = items[0]->row();
					//删除选中的行
					mResultTable->removeRow(index);
					mResultTable->setRowCount(max(m_testTableMinRow, m_testRecord.dataList().size()));
					try {
						//删除缓存的图片
						deleteImage(m_testRecord.testTime().date(), m_testRecord.testNum(), m_testRecord.dataList()[index].num());
						//删除数据库中的数据
						m_dao.deleteTestDataById(m_testRecord.dataList()[index].id());
						m_testRecord.dataList().removeAt(index);
						//判断是否还有数据,若没有数据则删除当前的记录
						if (m_testRecord.dataList().size() == 0) {
							//删除文件
							QString filePath = QString("%1/%2/%3").arg(m_config.cache.path).arg(m_testRecord.testTime().date().toString("yyyy-MM-dd")).arg(m_testRecord.testNum());
							FileUtils::deleteFiles(filePath);
							//删除数据库中的记录
							m_dao.deleteRecord(m_testRecord.id());
						}
					} catch (const std::exception& e) {
						qCritical() << e.what();
					}
					//清除选择的行
					mResultTable->clearSelection();
				}
			}
		}
	}, 50);
}

void AppWindow::on_mClearBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		if (m_testRecord.dataList().size() > 0 && MyMessageBox::warning(this, tr("是否要删除当前检测的记录"), tr("是"), tr("否"))) {
			QTableWidget* mResultTable = findChild<QTableWidget*>("mResultTable");
			//删除表格中的数据
			TableUtils::restTable(mResultTable, m_testTableMinRow);
			//清空缓存的数据
			m_testRecord.dataList().clear();
			try {
				//删除文件
				QString filePath = QString("%1/%2/%3").arg(m_config.cache.path).arg(m_testRecord.testTime().date().toString("yyyy-MM-dd")).arg(m_testRecord.testNum());
				FileUtils::deleteFile(filePath);
				//删除数据库中的记录
				m_dao.deleteRecord(m_testRecord.id());
			} catch (const std::exception& e) {
				qCritical() << e.what();
			}
		}
	}, 50);
}

void AppWindow::on_qConfirmBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		//检测输入日期
		QDate beginDay = findChild<QDateEdit*>("qBeginDateEdit")->date();
		QDate endDay = findChild<QDateEdit*>("qEndDateEdit")->date();
		if (endDay < beginDay) {
			MyMessageBox::warning(this, tr("请选择正确的日期"), tr("关闭"));
			return;
		}
		try {
			//查询结果
			QComboBox* qTesterComboBox = findChild<QComboBox*>("qTesterComboBox");
			QComboBox* qScheduleComboBox = findChild<QComboBox*>("qScheduleComboBox");
			QComboBox* qBrandComboBox = findChild<QComboBox*>("qBrandComboBox");
			queryTestRecord(beginDay, endDay, qTesterComboBox->currentText(), qScheduleComboBox->currentText(), qBrandComboBox->currentText());
		} catch (const RunError& e) {
			qCritical() << e.errorMsg();
			MyMessageBox::warning(this, "查询数据失败1", "关闭");
		} catch (const std::exception& e) {
			qCritical() << e.what();
			MyMessageBox::warning(this, "查询数据失败2", "关闭");
		}
	}, 100);
}

void AppWindow::on_qResetBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	//防止按钮重复提交
	singleClicked([&]() {
		qInfo() << tr("重置查询...");
		//重置日期
		QDate today = QDate::currentDate();
		findChild<QDateEdit*>("qBeginDateEdit")->setDate(today);
		findChild<QDateEdit*>("qEndDateEdit")->setDate(today);
		//重置检测员、牌号，班次信息
		findChild<QComboBox*>("qTesterComboBox")->setCurrentIndex(-1);
		findChild<QComboBox*>("qScheduleComboBox")->setCurrentIndex(-1);
		findChild<QComboBox*>("qBrandComboBox")->setCurrentIndex(-1);
	}, 500);
}

void AppWindow::on_qExportBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		//获取查询表格当前选择的行
		int row = findChild<QTableWidget*>("qResultTable")->selectedItems()[0]->row();
		//判断表格当前选择的行是否有数据
		if (row < m_queryResultList.size() && m_queryResultList[row].dataList().size() > 0) {
			DaoModel::TestRecord& record = m_queryResultList[row];
			//获取文件保存的文件夹
			QString filePath = QFileDialog::getExistingDirectory(this, QString("保存"), FileUtils::getDesktopPath());
			if (!filePath.isEmpty()) {
				//文件保存路径/项目名_检测日期_检测编号
				QString fileNmae = tr("%1/ECWS100_%2_%3.xlsx").arg(filePath).arg(record.testTime().toString("yyyyMMdd")).arg(record.testNum());
				try {
					ExcelUtils::saveExcel(record, fileNmae);
					MyMessageBox::information(this, tr("导出完成"), tr("关闭"));
				} catch (const std::exception& e) {
					qCritical() << e.what();
					MyMessageBox::warning(this, tr("导出失败"), tr("关闭"));
				}
			}
		} else {
			MyMessageBox::warning(this, tr("无可导出数据"), tr("关闭"));
			qWarning() << tr("无可导出数据");
		}
	}, 50);
}

void AppWindow::on_qPrintBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		//获取查询表格当前选择的行
		int row = findChild<QTableWidget*>("qResultTable")->selectedItems()[0]->row();
		//判断表格当前选择的行是否有数据
		if (row < m_queryResultList.size() && m_queryResultList[row].dataList().size() > 0) {
			PrinterManager::printDirect(m_queryResultList[row]);
		} else {
			MyMessageBox::warning(this, tr("没有数据可打印"), tr("关闭"));
			qWarning() << tr("没有数据可打印");
		}
	}, 50);
}

void AppWindow::on_qDeleteBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		QList<QTableWidgetItem*>& items = findChild<QTableWidget*>("qResultTable")->selectedItems();
		if (items.size() > 0 && items[0]->row() < m_queryResultList.size()) {
			int row = items[0]->row();
			if (MyMessageBox::warning(this, tr("是否要删除当前选择的记录"), tr("是"), tr("否"))) {
				//删除表格中的数据
				findChild<QTableWidget*>("qResultTable")->removeRow(row);
				findChild<QTableWidget*>("qResultTable")->setRowCount(max(m_historyTableMinRow, m_queryResultList.size()));
				//清空检测数据记录表格
				TableUtils::restTable(findChild<QTableWidget*>("qResultTable_2"), m_historyDataTableMinRow);
				try {
					//删除文件
					QString filePath = QString("%1/%2/%3").arg(m_config.cache.path).arg(m_queryResultList[row].testTime().date().toString("yyyy-MM-dd")).arg(m_queryResultList[row].testNum());
					FileUtils::deleteFile(filePath);
					//删除数据库中的数据
					m_dao.deleteRecord(m_queryResultList[row].id());
					m_queryResultList.removeAt(row);
				} catch (const std::exception& e) {
					qCritical() << e.what();
				}
				findChild<QTableWidget*>("qResultTable")->clearSelection();
			}
		}
	}, 500);
}

void AppWindow::on_qClearBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		if (m_queryResultList.size() > 0 && MyMessageBox::warning(this, tr("是否要删除当前所有的检测记录"), tr("是"), tr("否"))) {
			vector<qint64> ids;
			for (DaoModel::TestRecord& record : m_queryResultList) {
				ids.push_back(record.id());
				//删除文件
				QString filePath = QString("%1/%2/%3").arg(m_config.cache.path).arg(record.testTime().date().toString("yyyy-MM-dd")).arg(record.testNum());
				FileUtils::deleteFiles(filePath);
			}
			//删除数据
			try {
				m_dao.deleteRecords(ids);
			} catch (const std::exception& e) {
				qCritical() << e.what();
			}
			//删除表格中的数据
			TableUtils::restTable(findChild<QTableWidget*>("qResultTable"), m_historyTableMinRow);
			TableUtils::restTable(findChild<QTableWidget*>("qResultTable_2"), m_historyDataTableMinRow);
			findChild<QTableWidget*>("qResultTable")->clearSelection();
		}
	}, 500);
}

void AppWindow::on_qResultTable_cellClicked(int row, int column) {
	qInfo() << "m_queryResultList size: " << m_queryResultList.size() << ", row: " << row << ", column: " << column;
	singleClicked([&]() {
		try {
			if (row < m_queryResultList.size()) {
				//清空表格
				QTableWidget* qResultTable_2 = findChild<QTableWidget*>("qResultTable_2");
				qResultTable_2->model()->removeRows(0, qResultTable_2->rowCount());
				//获取被选取的记录
				DaoModel::TestRecord& record = m_queryResultList[row];
				record.dataList().clear();
				m_dao.queryTestData(record.dataList(), record.id());
				showTestData(qResultTable_2, record.dataList(), m_historyDataTableMinRow);
			}
		} catch (const std::exception& e) {
			qCritical() << e.what();
		}
	}, 500);
}

void AppWindow::on_sDelteTesterBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		QTableWidget* sTesterTableWidget = findChild<QTableWidget*>("sTesterTableWidget");
		QComboBox* mTesterComboBox = findChild<QComboBox*>("mTesterComboBox");
		//获取选中的行的数据
		QList<QTableWidgetItem*>& items = sTesterTableWidget->selectedItems();
		if (items.size() > 0 && items[1] != nullptr) {
			//获取名称
			QString name = items[1]->text();
			int row = items[0]->row();
			if (row < mTesterComboBox->count() && MyMessageBox::warning(this, tr("是否要删除检测员：%1").arg(name), tr("是"), tr("否"))) {
				try {
					//删除表格中的数据
					sTesterTableWidget->model()->removeRow(row);
					//删除选择框中的数据
					mTesterComboBox->removeItem(mTesterComboBox->findText(name));
					//删除数据库中的数据
					m_dao.deleteTestParam("tester", name);
					//重置表格行数
					sTesterTableWidget->setRowCount(max(mTesterComboBox->count(), m_testerTableMinRow));
				} catch (const std::exception& e) {
					qCritical() << e.what();
				}
				//清除选中的行
				sTesterTableWidget->clearSelection();
			}
		}
	}, 200);
}

void AppWindow::on_sDeleteBrandBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		QTableWidget* sBrandTableWidget = findChild<QTableWidget*>("sBrandTableWidget");
		QComboBox* mBrandComboBox = findChild<QComboBox*>("mBrandComboBox");
		//获取选中的行的数据
		QList<QTableWidgetItem*>& items = sBrandTableWidget->selectedItems();
		if (items.size() > 0 && items[1] != nullptr) {
			//获取名称
			QString name = items[1]->text();
			int row = items[0]->row();
			if (row < mBrandComboBox->count() && MyMessageBox::warning(this, tr("是否要删除牌号：%1").arg(name), tr("是"), tr("否"))) {
				try {
					//删除表格中的数据
					sBrandTableWidget->model()->removeRow(row);
					//删除选择框中的数据
					mBrandComboBox->removeItem(mBrandComboBox->findText(name));
					//删除数据库中的数据
					m_dao.deleteTestParam("brand", name);
					//重置表格行数
					sBrandTableWidget->setRowCount(max(mBrandComboBox->count(), m_brandTableMinRow));
				} catch (const std::exception& e) {
					qCritical() << e.what();
				}
				//清除选中的行
				sBrandTableWidget->clearSelection();
			}
		}
	}, 200);
}

void AppWindow::on_sDeleteScheduleBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		QTableWidget* sScheduleTableWidget = findChild<QTableWidget*>("sScheduleTableWidget");
		QComboBox* mScheduleComboBox = findChild<QComboBox*>("mScheduleComboBox");
		//获取选中的行的数据
		QList<QTableWidgetItem*>& items = sScheduleTableWidget->selectedItems();
		if (items.size() > 0 && items[1] != nullptr) {
			//获取名称
			QString name = items[1]->text();
			int row = items[0]->row();
			if (row < mScheduleComboBox->count() && MyMessageBox::warning(this, tr("是否要删除检测员：%1").arg(name), tr("是"), tr("否"))) {
				try {
					//删除表格中的数据
					sScheduleTableWidget->model()->removeRow(row);
					//删除选择框中的数据
					mScheduleComboBox->removeItem(mScheduleComboBox->findText(name));
					//删除数据库中的数据
					m_dao.deleteTestParam("schedule", name);
					//重置表格行数
					sScheduleTableWidget->setRowCount(max(mScheduleComboBox->count(), m_scheduleTableMinRow));
				} catch (const std::exception& e) {
					qCritical() << e.what();
				}
				//清除选中的行
				sScheduleTableWidget->clearSelection();
			}
		}
	}, 200);
}

void AppWindow::on_saveConfigBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		m_config.camera.exposure = ((SpinBox*)findChild<QWidget*>("cameraExposureTimeSpinBox"))->value();
		m_config.camera.gain = ((SpinBox*) findChild<QWidget*>("cameraGainSpinBox"))->value();
		try {
			//设置相机曝光
			m_scannerCamera.setExposureTime(m_config.camera.exposure);
			m_scannerCamera.setGain(m_config.camera.gain);
			//重新连接串口
			m_config.saveConfig();
			MyMessageBox::information(this, tr("参数更新完成"), tr("关闭"));
		} catch (const std::exception& e) {
			qCritical() << e.what();
		}
	}, 50);
}

void AppWindow::on_sMotoParamsSettingBtn_clicked() {
	try {
		m_serialPort.initParams(
			float(findChild<QSpinBox*>("sAcceleratedSpinBox")->value()),
			float(findChild<QSpinBox*>("sRetardedSpinBox")->value()),
			float(findChild<QSpinBox*>("sEQuickenSpinBox")->value()),
			float(findChild<QSpinBox*>("sEWorkSpinBox")->value()),
			float(findChild<QSpinBox*>("sEAwaitSpinBox")->value()),
			ushort(findChild<QSpinBox*>("sMotoMcsSpinBox")->value())
		);
	} catch (const RunError& e) {
		qCritical() << e.errorMsg();
		MyMessageBox::warning(this, e.errorMsg(), "关闭");
	} catch (const std::exception& e) {
		qCritical() << e.what();
		MyMessageBox::warning(this, e.what(), "关闭");
	} catch (...) {
		qCritical() << "UNKNOW ERROR";
		MyMessageBox::warning(this, "发生异常", "关闭");
	}
}

void AppWindow::on_sStopMoveBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	singleClicked([&]() {
		try {
			qInfo() << "[DEV] 停止电机移动...";
			//停止电机运动
			m_serialPort.stopMotor();
		} catch (const RunError& e) {
			qCritical() << e.errorMsg();
			MyMessageBox::warning(this, e.errorMsg(), "关闭");
		} catch (const std::exception& e) {
			qCritical() << e.what();
			MyMessageBox::warning(this, e.what(), "关闭");
		} catch (...) {
			qCritical() << "UNKNOW ERROR";
			MyMessageBox::warning(this, "发生异常", "关闭");
		}
	}, 50);
}

void AppWindow::on_sMotorToHeadBtn_clicked() {
	//qInfo() << sender()->objectName() << " pressed...";
	//if (!m_btnEnable) {
	//	return;
	//}
	//if (m_serialPort.isOpen()) {
	//	try {
	//		m_serialPort.moveMoto(float(findChild<QSpinBox*>("sBackSpeedSpinBox")->value()), SerialPort::POS_RESET);
	//		m_btnEnable = false;
	//		//计算运行时间
	//		//qint64 beginTime = TimeUtils::getTimeGen();
	//		//while (m_serialPort.getMotorPos() != 0) {
	//		//    QApplication::processEvents();
	//		//}
	//		//qDebug() << "move use time: " << (TimeUtils::getTimeGen() - beginTime);
	//	} catch (const RunError& e) {
	//		qCritical() << e.errorMsg();
	//		MyMessageBox::warning(this, e.errorMsg(), "关闭");
	//	} catch (const std::exception& e) {
	//		qCritical() << e.what();
	//		MyMessageBox::warning(this, e.what(), "关闭");
	//	} catch (...) {
	//		qCritical() << "UNKNOW ERROR";
	//		MyMessageBox::warning(this, "发生异常", "关闭");
	//	}
	//} else {
	//	MyMessageBox::warning(this, "串口未连接", "关闭");
	//}
	//m_btnEnable = true;

	m_serialPort.resetMoto();

}

void AppWindow::on_sMotorToTailBtn_pressed() {
	//qInfo() << sender()->objectName() << " pressed...";
	//if (!m_btnEnable) {
	//	return;
	//}
	//if (m_serialPort.isOpen()) {
	//	try {
	//		m_serialPort.moveMoto(float(findChild<QSpinBox*>("sScanSpeedSpinBox")->value()), SerialPort::POS_TAIL);
	//		m_btnEnable = false;
	//		//计算运行时间
	//		//qint64 beginTime = TimeUtils::getTimeGen();
	//		//while (m_serialPort.getMotorPos() != 1) {
	//		//    QApplication::processEvents();
	//		//}
	//		//qDebug() << "move use time: " << (TimeUtils::getTimeGen() - beginTime);
	//	} catch (const RunError& e) {
	//		qCritical() << e.errorMsg();
	//		MyMessageBox::warning(this, e.errorMsg(), "关闭");
	//	} catch (const std::exception& e) {
	//		qCritical() << e.what();
	//		MyMessageBox::warning(this, e.what(), "关闭");
	//	} catch (...) {
	//		qCritical() << "UNKNOW ERROR";
	//		MyMessageBox::warning(this, "发生异常", "关闭");
	//	}
	//} else {
	//	MyMessageBox::warning(this, "串口未连接", "关闭");
	//}
	//m_btnEnable = true;

	//m_serialPort.motorDisabling();
	//m_serialPort.moveMotoToTail();








}

void AppWindow::on_sMotorToTailBtn_released() {
	qInfo() << sender()->objectName() << " released...";
	try {
		//停止电机运动
		m_serialPort.stopMotor();
	} catch (const RunError& e) {
		qCritical() << e.errorMsg();
	} catch (const std::exception& e) {
		qCritical() << e.what();
	} catch (...) {
		qCritical() << "UNKNOW ERROR";
	}
}

void AppWindow::on_sCaptureBtn_clicked() {
	//获取文件保存的文件夹
	QString filePath = QFileDialog::getSaveFileName(this, QString("保存"), FileUtils::getDesktopPath(), "*.jpg");
	if (!filePath.isEmpty()) {
		cv::Mat frame;
		//获取侧边图像
		m_sliderCapture.getFrame(frame);
		if (!frame.empty()) {
			//获取保存路径
			cv::imwrite(filePath.toStdString(), frame);
		} else {
			MyMessageBox::warning(this, "保存失败", "关闭");
		}
	}
}

void AppWindow::on_demarcateConfirmBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	if (!m_btnEnable) {
		return;
	}
	singleClicked([&]() {
		bool status = false;
		QString errorMsg;
		try {
			cv::Mat scannerImage1, scannerImage2;
			//扫描图像
			startImageScan(scannerImage1, scannerImage2);
			//若扫描的图像不为空，则将图像传入编辑对话框中等待编辑
			if (!scannerImage1.empty() && !scannerImage2.empty()) {
				//获取标准件的尺寸
				double width = ((DoubleSpinBox*)findChild<QWidget*>("dWidthDoubleSpinBox"))->value();
				double length = ((DoubleSpinBox*) findChild<QWidget*>("dLengthDoubleSpinBox"))->value();
				if (width > 0 && length > 0) {
					//传入图片
					cv::Mat image = scannerImage1 - scannerImage2;
					//输出结果
					double x = 0, y = 0;
					status = ImageUtils::cameraDemarcate(image, width, length, x, y);
					if (status) {
						m_config.camera.pixsizeX = x;
						m_config.camera.pixsizeY = y;
						m_config.saveConfig();
					}
				} else {
					errorMsg = "请输入标准件参数";
				}
			} else {
				errorMsg = "扫描失败";
			}
		} catch (const RunError& e) {
			qCritical() << e.errorMsg();
			errorMsg = e.errorMsg();
		} catch (const std::exception& e) {
			qCritical() << e.what();
			errorMsg = "未知异常";
		}
		//判断是否校准成功
		if (status) {
			MyMessageBox::information(this, tr("校准成功"), tr("关闭"));
			findChild<QLabel*>("demarcateResultLabel")->setText(tr("%1mm/pix")
																.arg(QString::number((m_config.camera.pixsizeX + m_config.camera.pixsizeY) / 2.0f, 'f', 3)));
		} else {
			MyMessageBox::warning(this, errorMsg, tr("关闭"));
		}
	}, 50);
}

void AppWindow::on_demarcateCheckBtn_clicked() {
	qInfo() << sender()->objectName() << " clicked...";
	if (!m_btnEnable) {
		return;
	}
	singleClicked([&]() {
		bool status = false;
		QString errorMsg;
		try {
			//扫描图像
			cv::Mat scannerImage1, scannerImage2;
			startImageScan(scannerImage1, scannerImage2);
			//若扫描的图像不为空，则将图像传入编辑对话框中等待编辑
			if (!scannerImage1.empty() && !scannerImage2.empty()) {
				//传入图片
				cv::Mat image = scannerImage1 - scannerImage2;
				double length = 0, width = 0;
				status = ImageUtils::cameraDemarcate(image, 0, 0, length, width);
				if (status) {
					length = length * m_config.camera.pixsizeX;
					width = width * m_config.camera.pixsizeY;
					findChild<QLabel*>("demarcateCheckLabel")->setText(tr("长度：%1mm,  宽度：%2mm")
																	   .arg(QString::number(length, 'f', 3))
																	   .arg(QString::number(width, 'f', 3)));
				} else {
					errorMsg = "校验失败";
				}
			} else {
				errorMsg = "扫描失败";
			}
		} catch (const RunError& e) {
			qCritical() << e.errorMsg();
			errorMsg = e.errorMsg();
		} catch (const std::exception& e) {
			qCritical() << e.what();
			errorMsg = "未知异常";
		}
		//判断是否校准成功
		if (status) {
			MyMessageBox::information(this, tr("校验完成"), tr("关闭"));
		} else {
			MyMessageBox::warning(this, errorMsg, tr("关闭"));
		}
	}, 50);

}



///////////////////////////////////////////////////////////////////////////////////////////////////
///										DefaultWindow											///
///////////////////////////////////////////////////////////////////////////////////////////////////

DefaultWindow::DefaultWindow(SplashScreen& splash, QWidget* parent) : AppWindow(splash, parent) {
	m_ui.setupUi(this);
	m_ui.stackedWidget->setCurrentIndex(0);
	m_ui.contentWidget->setCurrentIndex(0);
	//initTable();
	//测量结果表格最少的行数
	m_testTableMinRow = 10;
	//历史记录表默认行数
	m_historyTableMinRow = 13;
	//历史记录表默认行数
	m_historyDataTableMinRow = 12;
	//牌号信息表格默认行数
	m_brandTableMinRow = 12;
	//检测员信息表格默认行数
	m_testerTableMinRow = 12;
	//班次表格默认行数
	m_scheduleTableMinRow = 12;
}

void DefaultWindow::initTable() {
	AppWindow::initTable();
	//检测记录表格
	QTableWidget* table = findChild<QTableWidget*>("mResultTable");
	//设置列宽
	table->setColumnWidth(0, 60);
	table->setColumnWidth(1, 130);
	table->setColumnWidth(2, 130);
	table->setColumnWidth(3, 130);
	table->setColumnWidth(4, 130);
	table->setColumnWidth(5, 130);
	table->setColumnWidth(6, 130);
	table->setColumnWidth(7, 130);

	//历史记录表格
	table = findChild<QTableWidget*>("qResultTable");
	table->setColumnWidth(0, 60);
	table->setColumnWidth(1, 240);
	table->setColumnWidth(2, 130);
	table->setColumnWidth(3, 130);
	table->setColumnWidth(4, 130);

	//历史数据表格
	table = findChild<QTableWidget*>("qResultTable_2");
	//设置列宽
	table->setColumnWidth(0, 60);
	table->setColumnWidth(1, 130);
	table->setColumnWidth(2, 130);
	table->setColumnWidth(3, 130);
	table->setColumnWidth(4, 130);
	table->setColumnWidth(5, 130);
	table->setColumnWidth(6, 130);
	table->setColumnWidth(7, 130);
}


///////////////////////////////////////////////////////////////////////////////////////////////////
///										ExtendWindow											///
///////////////////////////////////////////////////////////////////////////////////////////////////


ExtendWindow::ExtendWindow(SplashScreen& splash, QWidget* parent) : AppWindow(splash, parent) {
	m_ui.setupUi(this);
	m_ui.stackedWidget->setCurrentIndex(0);
	m_ui.contentWidget->setCurrentIndex(0);
	//initTable();
	//测量结果表格最少的行数
	m_testTableMinRow = 13;     
	//历史记录表默认行数
	m_historyTableMinRow = 23;     
	//历史记录表默认行数
	m_historyDataTableMinRow = 23; 
	//牌号信息表格默认行数
	m_brandTableMinRow = 11;    
	//检测员信息表格默认行数
	m_testerTableMinRow = 11; 
	//班次表格默认行数
	m_scheduleTableMinRow = 11;     
}

void ExtendWindow::initTable() {
	AppWindow::initTable();
}

